// @Describe: 消息文件发送模块
package core

import (
	"bufio"
	"context"
	"errors"
	"github.com/rs/zerolog/log"
	"github.com/spf13/viper"
	"io"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"wormhole/pkg/clientx"
	"wormhole/protos/hole"
	"wormhole/utils"
)

//自动检测文件或文本消息进行发送
func (s *holeServer) SendAuto(message *hole.Message, autoServer hole.Hole_SendAutoServer) error {
	log.Trace().Msg("send auto")
	if utils.IsExistPath(message.Data) {
		log.Trace().Msg("auto send file")
		return s.SendFile(message, autoServer)
	} else {
		log.Trace().Msg("auto send text")
		_, err := s.SendText(context.Background(), message)
		if err != nil {
			return err
		}
		return nil
	}
}

// SendText
//  @Description: 发送文本信息
//  @receiver s
//  @param ctx
//  @param message
//  @return error
func (s *holeServer) SendText(ctx context.Context, message *hole.Message) (*hole.Reply, error) {
	key := s.destParseKey(message.To)
	if ok := s.FillDeviceKey(key); ok {
		err := s.sendText(ctx, message.Data, key.Ripple)
		if err != nil {
			return nil, err
		}
	} else {
		return nil, errors.New("FillDeviceKey fail")
	}
	return new(hole.Reply), nil
}

// SendFile
//  @Description: 发送文件数据服务
//  @receiver s
//  @param message 文件路径消息
//  @param svc 传输进度数据流
//  @return error
func (s *holeServer) SendFile(message *hole.Message, sendFileServer hole.Hole_SendFileServer) error {
	key := s.destParseKey(message.To)
	if ok := s.FillDeviceKey(key); ok {
		err := s.sendFiles(sendFileServer, message.Data, key.Ripple)
		if err != nil {
			return err
		}
	} else {
		return errors.New("FillDeviceKey fail")
	}
	return nil
}

// sendText
//  @Description: 连接远程acceptText服务,发送文本消息
//  @receiver s
//  @param ctx
//  @param text
//  @param ripple
//  @return error
func (s *holeServer) sendText(ctx context.Context, text string, ripple *hole.Ripple) error {
	c, err := clientx.NewRippleClient(ripple)
	if err != nil {
		return err
	}
	defer c.Close()
	textMessage := &hole.TextMessage{
		FromIp: viper.GetString("core.ip"),
		Text:   text,
	}
	_, err = c.AcceptText(ctx, textMessage)
	if err != nil {
		return err
	}
	return nil
}

// sendFiles
//  @Description: 发送多文件
//  @receiver s
//  @param targetFile
//  @param ripple
func (s *holeServer) sendFiles(sendFileServer hole.Hole_SendFileServer, targetPath string, ripple *hole.Ripple) error {
	//根文件名称
	ads, err := filepath.Abs(targetPath)
	if err != nil {
		return err
	}
	ads = strings.ReplaceAll(ads, `\`, `/`)
	fileKey := path.Base(ads)
	//判断文件类型,添加子文件路径
	state, err := os.Stat(targetPath)
	if err != nil {
		return err
	}
	filePaths := make(map[string]string, 0)
	if state.IsDir() {
		filePaths, err = utils.GetAllFileSubPath(fileKey, targetPath)
		if err != nil {
			return err
		}
	} else {
		filePaths = map[string]string{targetPath: ""}
	}

	//连接rpc准备发送数据
	c, err := clientx.NewRippleClient(ripple)
	if err != nil {
		return err
	}
	putStream, err := c.AcceptFile(context.Background())
	if err != nil {
		return err
	}
	defer putStream.CloseSend()
	// 构造消息信息
	message := &hole.FileMessage{
		Key:    fileKey,
		FromIp: viper.GetString("core.ip"),
	}
	progress := &hole.Progress{
		Total: int64(len(filePaths)),
	}

	// todo: 并发提速
	for realFilePath, softFilePath := range filePaths {
		// 传输进度
		progress.Index++ // 传输文件
		message.Path = softFilePath
		if softFilePath == "" {
			message.Num = 0
		} else {
			message.Num = int64(len(filePaths))
		}
		err := s.sendFile(putStream, sendFileServer, realFilePath, message, progress)
		if err != nil {
			return err
		}
	}
	return nil
}

// sendFile
//  @Description: 发送单文件数据,只处理文件数据,不处理消息元数据
//  @receiver s
//  @param putStream
//  @param realFilePath
//  @param message
//  @return error
func (s *holeServer) sendFile(putStream hole.Hole_AcceptFileClient,
	sendFileServer hole.Hole_SendFileServer,
	realFilePath string, message *hole.FileMessage, progress *hole.Progress) error {
	// 打开文件句柄
	f, err := os.Open(realFilePath)
	if err != nil {
		return err
	}
	defer f.Close()
	reader := bufio.NewReader(f)
	//填充要发送的元数据
	state, err := os.Stat(realFilePath)
	if err != nil {
		return err
	}
	message.Size = state.Size()
	message.Perm = int32(state.Mode().Perm())
	progress.Size = message.Size
	progress.Current = 0
	// 发送数据
	for i := 0; ; i++ {
		buf := make([]byte, 4096)
		// 从file读取到buf中
		n, err := reader.Read(buf)
		// 读取结束
		if errors.Is(err, io.EOF) {
			return nil
		} else if err != nil {
			log.Err(err).Send()
			return err
		}
		//流传输
		message.Data = buf[:n]
		err = putStream.Send(message)
		if err != nil {
			return err
		}
		progress.Current += int64(n)
		sendFileServer.Send(progress)
	}
}

// destParseKey
//  @Description: 解析目标设备key
//  @receiver s
//  @param dest
//  @return *hole.DeviceKey
func (s *holeServer) destParseKey(dest string) *hole.DeviceKey {
	key := &hole.DeviceKey{
		Ripple: &hole.Ripple{},
		Index:  0,
	}
	// 匹配ip和序号的正则
	regIp := regexp.MustCompile(`^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}:*\d{0,5}$`) //ip或者ip:port
	regIndex := regexp.MustCompile(`^\d+$`)

	if regIp.Match([]byte(dest)) {
		// ip
		sp := strings.Split(dest, ":")
		key.Ripple.Ip = sp[0]
		if len(sp) == 2 {
			port, err := strconv.Atoi(sp[1])
			if err == nil {
				key.Ripple.Port = int32(port)
			}
		}
	} else if regIndex.Match([]byte(dest)) {
		// index
		index, err := strconv.Atoi(dest)
		if err != nil {
			log.Err(err).Send()
			return nil
		}
		key.Index = int32(index)
	} else {
		// name
		key.Ripple.Name = dest
	}
	return key
}
